using System;
using System.Collections;
using System.Collections.Generic;
using Main.CropPlant;
using Main.Details;
using Main.Event;
using Main.Save;
using Main.Transition;
using UnityEngine;
using UnityEngine.Tilemaps;
using ZSW.Framework;

namespace Main.Map
{
    public class GridMapManager : ZSWF_Singleton<GridMapManager>, ISaveable
    {
        [Header("瓦片地图")]
        public RuleTile digTile;
        public RuleTile waterTile;
        private Tilemap digTileMap;
        private Tilemap waterTileMap;


        [Header("地图信息")]
        public List<MapData_SO> mapDataList;

        /// <summary>
        /// key: 地图名加坐标
        /// </summary>
        private Dictionary<string, TileDetails> tileDetailsDict = new Dictionary<string, TileDetails>();

        public static Grid CurrentGrid;
        private Season CurrentSeason;
        private Dictionary<string, bool> mapLoadedDict = new Dictionary<string, bool>();
        private List<ReapItem> reapItems;

        public string GUID => GetComponent<DataGUID>().guid;

        public override void Init()
        {
            base.Init();
            foreach (var mapData in mapDataList)
            {
                InitTileDetailsDic(mapData);
                mapLoadedDict.Add(mapData.sceneName, false);
            }

            MainEventSystem.ExecuteActionAfterAnimation += OnExecuteActionAfterAnimation;
            MainEventSystem.AfterLoadSceneEvent += OnAfterLoadSceneEvent;
            MainEventSystem.GameDateEvent += OnGameDateEvent;
            MainEventSystem.RefreshMapEvent += RefreshMap;

            ISaveable saveable = this;
            saveable.RegisterSaveable();
        }

        private void OnGameDateEvent(int day, int mouth, int year, Season season)
        {
            CurrentSeason = season;

            foreach (var tile in tileDetailsDict.Values)
            {
                if (tile.daysSinceWatered > -1)
                {
                    tile.daysSinceWatered = -1;
                }

                if (tile.daysSinceDug > -1)
                {
                    tile.daysSinceDug++;
                }

                // 挖地超时判断
                if (tile.daysSinceDug > 5 && tile.seedItemID == -1)
                {
                    tile.daysSinceDug = -1;
                    tile.canDig = true;
                    tile.growDays = -1;
                }

                if (tile.seedItemID != -1)
                {
                    tile.growDays++;
                }
            }

            if (mapLoadedDict.TryGetValue(SceneTransitionManager.CurrentScene, out var isLoad))
            {
                if (!isLoad)
                {
                    mapLoadedDict[SceneTransitionManager.CurrentScene] = true;
                    MainEventSystem.CallGenerateCropEvent();
                }
            }

            RefreshMap();
        }

        private void OnAfterLoadSceneEvent()
        {
            CurrentGrid = FindObjectOfType<Grid>();
            digTileMap = GameObject.FindWithTag(Settings.DigTag).GetComponent<Tilemap>();
            waterTileMap = GameObject.FindWithTag(Settings.WaterTag).GetComponent<Tilemap>();
            DisplayMap();
        }

        /// <summary>
        /// 执行动作后事件,执行item的功能
        /// </summary>
        /// <param name="mouseWorldPos"></param>
        /// <param name="item"></param>
        private void OnExecuteActionAfterAnimation(Vector3 mouseWorldPos, ItemDetails item)
        {

            var mouseGridPos = CurrentGrid.WorldToCell(mouseWorldPos);

            if (TryGetCurrentSceneTileDetails(mouseGridPos, out var tileDetails))
            {
                // WORKFLOW: 根据物品类型执行对应功能
                switch (item.ItemType)
                {
                    case ItemType.Seed:
                        MainEventSystem.CallPlantSeedEvent(item.ItemID, tileDetails);
                        MainEventSystem.CallDropItemEvent(item.ItemID, mouseWorldPos, item.ItemType);
                        MainEventSystem.CallPlaySoundEvent(SoundName.Plant);
                        break;
                    case ItemType.Commodity:
                        MainEventSystem.CallDropItemEvent(item.ItemID, mouseWorldPos, item.ItemType);
                        break;
                    case ItemType.HoeTool:
                        SetDigTile(tileDetails);
                        tileDetails.daysSinceDug = 0;
                        tileDetails.canDig = false;
                        tileDetails.canDropItem = false;
                        //TODO: 添加音效
                        MainEventSystem.CallPlaySoundEvent(SoundName.Hoe);
                        break;
                    case ItemType.WaterTool:
                        SetWaterTile(tileDetails);
                        tileDetails.daysSinceWatered = 0;
                        //TODO: 添加音效
                        MainEventSystem.CallPlaySoundEvent(SoundName.Water);
                        break;
                    case ItemType.BreakTool:
                    case ItemType.ChopTool:
                        if (TryGetCrop(mouseWorldPos, out var crop))
                        {
                            crop.ProcessToolAction(item, crop.tileDetails);
                            MainEventSystem.CallPlaySoundEvent(SoundName.Chop);
                        }
                        break;
                    case ItemType.CollectTool:
                        if (TryGetCrop(mouseWorldPos, out crop))
                        {
                            crop.ProcessToolAction(item, tileDetails);
                        }
                        break;
                    case ItemType.ReapTool:
                        var count = 0;
                        for (int i = 0; i < reapItems.Count; i++)
                        {
                            ReapItem reapItem = reapItems[i];
                            MainEventSystem.CallParticleEffectEvent(ParticleEffectType.ReapableScenery, reapItem.transform.position);
                            reapItem.SpawnHarvestItems();
                            Destroy(reapItem.gameObject);
                            count++;
                            if (count >= Settings.reapAmount)
                            {
                                break;
                            }
                        }
                        break;
                    case ItemType.Furniture:
                        // 地图生成物品
                        // 移除背包资源
                        // 移除指定资源
                        MainEventSystem.CallBuildFurniture(mouseWorldPos, item.ItemID);
                        break;
                }
                UpdateTileDetails(tileDetails);
            }
        }

        public bool TryGetCrop(Vector3 mouseWorldPos, out Crop crop)
        {
            Collider2D[] colliders = Physics2D.OverlapPointAll(mouseWorldPos);

            crop = null;

            foreach (var col in colliders)
            {
                if (col.TryGetComponent(out crop))
                {
                    break;
                }
            }
            return crop != null;
        }

        /// <summary>
        /// 获取指定工具范围内的所有Reapable类型的Item
        /// </summary>
        /// <param name="tool"></param>
        /// <returns></returns>
        public bool HaveReapableItemsInRadius(Vector3 mouseWorldPos, ItemDetails tool)
        {
            reapItems = new List<ReapItem>();

            Collider2D[] colliders = new Collider2D[20];
            Physics2D.OverlapCircleNonAlloc(mouseWorldPos, tool.ItemUseRadius, colliders);
            if (colliders.Length > 0)
            {
                foreach (var col in colliders)
                {
                    if (col != null && col.TryGetComponent(out ReapItem item))
                    {
                        reapItems.Add(item);
                    }
                }
            }

            return reapItems.Count > 0;
        }

        /// <summary>
        /// 初始化 TileDetails 字典
        /// </summary>
        /// <param name="mapData"></param>
        private void InitTileDetailsDic(MapData_SO mapData)
        {
            // 遍历重复坐标的数据, 将同一块坐标的属性添加到TileDetails中
            foreach (var tileProperty in mapData.tileProperties)
            {
                // 字典Key 生成
                string key = mapData.sceneName + "x" + tileProperty.tileCoordinate.x + "y" + tileProperty.tileCoordinate.y;

                if (TryGetTileDetails(key, out TileDetails tileDetails))
                {
                    tileDetails.SetProperty(tileProperty);
                    tileDetailsDict[key] = tileDetails;
                }
                else
                {
                    tileDetails = new TileDetails()
                    {
                        girdX = tileProperty.tileCoordinate.x,
                        girdY = tileProperty.tileCoordinate.y,
                    };

                    tileDetails.SetProperty(tileProperty);
                    tileDetailsDict.Add(key, tileDetails);
                }
            }
        }

        public bool TryGetTileDetails(string key, out TileDetails tileDetails)
        {
            if (tileDetailsDict.ContainsKey(key))
            {
                tileDetails = tileDetailsDict[key];
                return true;
            }
            else
            {
                tileDetails = null;
                return false;
            }
        }

        public bool TryGetCurrentSceneTileDetails(Vector3Int mouseGridPos, out TileDetails tileDetails)
        {
            string key = SceneTransitionManager.CurrentScene + "x" + mouseGridPos.x + "y" + mouseGridPos.y;
            return TryGetTileDetails(key, out tileDetails);
        }

        public void SetDigTile(TileDetails tile)
        {
            var pos = new Vector3Int(tile.girdX, tile.girdY, 0);
            if (digTileMap != null)
                digTileMap.SetTile(pos, digTile);
        }

        public void SetWaterTile(TileDetails tile)
        {
            var pos = new Vector3Int(tile.girdX, tile.girdY, 0);
            if (waterTileMap != null)
                waterTileMap.SetTile(pos, waterTile);
        }

        /// <summary>
        /// 更新瓦片信息
        /// </summary>
        /// <param name="tileDetails"></param>
        public void UpdateTileDetails(TileDetails tileDetails)
        {
            string key = SceneTransitionManager.CurrentScene + "x" + tileDetails.girdX + "y" + tileDetails.girdY;
            if (tileDetailsDict.ContainsKey(key))
            {
                tileDetailsDict[key] = tileDetails;
            }
            else
            {
                tileDetailsDict.Add(key, tileDetails);
            }
        }

        /// <summary>
        /// 重置地图
        /// </summary>
        private void RefreshMap()
        {
            if (digTileMap != null)
            {
                digTileMap.ClearAllTiles();
            }
            if (waterTileMap != null)
            {
                waterTileMap.ClearAllTiles();
            }

            foreach (var crop in FindObjectsOfType<Crop>())
            {
                Destroy(crop.gameObject);
            }

            DisplayMap();
        }

        /// <summary>
        /// 显示地图
        /// </summary>
        private void DisplayMap()
        {
            string sceneName = SceneTransitionManager.CurrentScene;
            foreach (var tile in tileDetailsDict)
            {
                if (tile.Key.Contains(sceneName))
                {
                    if (tile.Value.daysSinceDug > -1)
                    {
                        SetDigTile(tile.Value);
                    }
                    if (tile.Value.daysSinceWatered > -1)
                    {
                        SetWaterTile(tile.Value);
                    }
                    if (tile.Value.seedItemID != -1)
                    {
                        MainEventSystem.CallPlantSeedEvent(tile.Value.seedItemID, tile.Value);
                    }
                }
            }
        }

        public bool TryGetGridDimensions(string sceneName, out RectInt gridRect)
        {
            gridRect = new RectInt();

            foreach (var mapData in mapDataList)
            {
                if (mapData.sceneName == sceneName)
                {
                    gridRect = mapData.Map;

                    return true;
                }
            }
            return false;
        }

        public GameSaveData GenerateSaveData()
        {
            var data = new GameSaveData();
            data.tileDetailsDict = tileDetailsDict;
            data.mapLoadedDict = mapLoadedDict;
            return data;
        }

        public void RestoreData(GameSaveData data)
        {
            tileDetailsDict = data.tileDetailsDict;
            mapLoadedDict = data.mapLoadedDict;
        }
    }
}

